﻿//-----------------------------------------------------------------------
// <copyright file="MessageDialog.cs" company="In The Hand Ltd">
//     Copyright © 2012-15 In The Hand Ltd. All rights reserved.
// </copyright>
//-----------------------------------------------------------------------

namespace InTheHand.UI.Popups
{
    using System;
    using System.Collections.Generic;
    using System.Threading.Tasks;

#if __IOS__
    using UIKit;
#endif

#if WINDOWS_PHONE
    using Windows.Foundation;
#endif
    /// <summary>
    /// Represents a dialog.
    /// </summary>
    /// <remarks>
    /// The dialog has a command bar that can support up to three commands.
    /// If you don't specify any commands, then a default command is added to close the dialog.
    /// <para>The dialog dims the screen behind it and blocks touch events from passing to the app's canvas until the user responds.</para>
    /// <para>Message dialogs should be used sparingly, and only for critical messages or simple questions that must block the user's flow.</para>
    /// </remarks>
    public sealed class MessageDialog
    {
#if WINDOWS_PHONE
        private const int MaxCommands = 2;
#else
        private const int MaxCommands = 3;
#endif
       
#if __IOS__
        UIAlertController uac = null;

        private void ActionClicked(UIAlertAction action)
        {
            // find the equivalent "metro" command and call the event handler
            for(int i = 0; i < uac.Actions.Length; i++)
            {
                if(uac.Actions[i] == action)
                {
                    if (Commands[i].Invoked != null)
                    {
                        Commands[i].Invoked(Commands[i]);
                    }

                    break;
                }
            }
        }
#endif

        /// <summary>
        /// Initializes a new instance of the <see cref="MessageDialog"/> class to display an untitled message dialog box that can be used to ask your user simple questions.
        /// </summary>
        /// <param name="content">The message you want displayed to the user.</param>
        public MessageDialog(string content) : this(content, string.Empty)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="MessageDialog"/> class to display a titled message dialog box that can be used to ask your user simple questions.
        /// </summary>
        /// <param name="content">The message you want displayed to the user.</param>
        /// <param name="title">The title you want displayed on the dialog box.</param>
        public MessageDialog(string content, string title)
        {
            this.Content = content;
            this.Title = title;
        }

        /// <summary>
        /// Begins an asynchronous operation showing a dialog.
        /// </summary>
        /// <returns>An object that represents the asynchronous operation.
        /// For more on the async pattern, see Asynchronous programming in the Windows Runtime.</returns>
        /// <remarks>In some cases, such as when the dialog is closed by the system out of your control, your result can be an empty command.
        /// <see cref="IAsyncOperation{TResult}.GetResults()"/> returns either the command selected which destroyed the dialog, or an empty command.
        /// For example, a dialog hosted in a charms window will return an empty command if the charms window has been dismissed.</remarks>
#if WINDOWS_PHONE
        public IAsyncOperation<IUICommand> ShowAsync()
#else
        public async Task<IUICommand> ShowAsync()
#endif    
        {
            if (this.Commands.Count > MaxCommands)
            {
                throw new InvalidOperationException();
            }
            
#if ANDROID
            Android.App.AlertDialog.Builder builder = new Android.App.AlertDialog.Builder(InTheHand.Foundation.ActivityInTheHand.CurrentContext);
            Android.App.AlertDialog dialog = builder.Create();
            dialog.SetTitle(this.Title);
            dialog.SetMessage(this.Content);
            if (Commands.Count == 0)
            {
                dialog.SetButton(-1, "Close", (EventHandler<Android.Content.DialogClickEventArgs>)null);
            }
            else
            {
                for (int i = 0; i < this.Commands.Count; i++)
                {
                    dialog.SetButton(-1 - i, this.Commands[i].Label, new EventHandler<Android.Content.DialogClickEventArgs>(Clicked));
                }
            }
            dialog.Show();
#elif __IOS__
            uac = UIAlertController.Create(this.Title, this.Content, UIAlertControllerStyle.Alert);
            if (Commands.Count == 0)
            {
                uac.AddAction(UIAlertAction.Create("Close", UIAlertActionStyle.Cancel | UIAlertActionStyle.Default, null));
            }
            else
            {
                for (int i = 0; i < this.Commands.Count; i++)
                {
                    UIAlertAction action = UIAlertAction.Create(this.Commands[i].Label, (UIAlertActionStyle)0, ActionClicked);
                    uac.AddAction(action);
                }
            }
            UIViewController currentController = UIApplication.SharedApplication.KeyWindow.RootViewController;
            while (currentController.PresentedViewController != null)
                currentController = currentController.PresentedViewController;

            currentController.PresentViewController(uac, true, null);
            return null;

#elif WINDOWS_PHONE
            List<string> buttons = new List<string>();
            foreach(IUICommand uic in this.Commands)
            {
                buttons.Add(uic.Label);
            }

            if (buttons.Count == 0)
            {
                buttons.Add(Resources.Resources.Close);
            }

            MessageDialogAsyncOperation asyncOperation = new MessageDialogAsyncOperation(this);

            string contentText = this.Content;

            // trim message body to 255 chars
            if (contentText.Length > 255)
            {
                contentText = contentText.Substring(0, 255);
            }

            Microsoft.Xna.Framework.GamerServices.Guide.BeginShowMessageBox(
                        string.IsNullOrEmpty(this.Title) ? " " : this.Title,
                        contentText,
                        buttons,
                        this.DefaultCommandIndex, // can choose which button has the focus
                        Microsoft.Xna.Framework.GamerServices.MessageBoxIcon.None, // can play sounds
                        result =>
                        {
                            int? returned = Microsoft.Xna.Framework.GamerServices.Guide.EndShowMessageBox(result);
                            // process and fire the required handler
                            if (returned.HasValue)
                            {
                                if (Commands.Count > returned.Value)
                                {
                                    IUICommand theCommand = Commands[returned.Value];
                                    asyncOperation.SetResults(theCommand);
                                    if (theCommand.Invoked != null)
                                    {
                                        theCommand.Invoked(theCommand);
                                    }
                                }
                                else
                                {
                                    asyncOperation.SetResults(null);
                                }
                            }
                            else
                            {
                                asyncOperation.SetResults(null);
                            }
                        }, null);

            return asyncOperation;
#else
            MessageDialogForm mdf = new MessageDialogForm(this);
            mdf.Show();
#endif
        }

#if ANDROID
        private void Clicked(object sender, Android.Content.DialogClickEventArgs e)
        {
            IUICommand theCommand = Commands[-1 - e.Which];
            if (theCommand.Invoked != null)
            {
                theCommand.Invoked(theCommand);
            }
        }
#endif

        #region Commands

        private List<IUICommand> commands = new List<IUICommand>();

        /// <summary>
        /// Gets the set of commands that appear in the command bar of the message dialog.
        /// </summary>
        /// <remarks>This is the array of commands that makes the dialog actionable.
        /// Get this array and add your dialog commands to it.</remarks>
        /// <value>The commands.</value>
        public IList<IUICommand> Commands
        {
            get
            {
                return this.commands;
            }
        }
        #endregion

        /// <summary>
        /// Gets or sets the message to be displayed to the user.
        /// </summary>
        /// <value>The message to be displayed to the user.</value>
        /// <remarks>Use the content to convey the objective of the dialog.
        /// Present the message, error or blocking question as simply as possible without extraneous information.
        /// <para>When a title is used, use the content to present additional information helpful to understanding or using the dialog.
        /// You can use this area to provide more detail or define terminology.
        /// Don't repeat the title with slightly different wording.</para></remarks>
        public string Content { get; set; }

        private int defaultCommandIndex;

        /// <summary>
        /// Gets or sets the index of the command you want to use as the default.
        /// This is the command that fires by default when users press the ENTER key instead of a specific command, for example.
        /// </summary>
        /// <remarks>Add the commands before you set the index.</remarks>
        /// <value>The index of the default command.</value>
        public int DefaultCommandIndex
        {
            get
            {
                return this.defaultCommandIndex;
            }

            set
            {
                if (value < 0 || value >= this.Commands.Count)
                {
                    throw new ArgumentOutOfRangeException();
                }

                this.defaultCommandIndex = value;
            }
        }

        /// <summary>
        /// Gets or sets the title to display on the dialog box, if any. 
        /// </summary>
        /// <value>The title you want to display on the dialog.
        /// If the title is not set, this will return an empty string.</value>
        /// <remarks>Use the title as a concise main instruction to convey the objective of the dialog.
        /// <para>Long titles do not wrap and will be truncated.</para>
        /// <para>If you're using the dialog to deliver a simple message, error or question, omit the title.
        /// Rely on the <see cref="Content"/> to deliver that core information.</para></remarks>
        public string Title { get; set; }

    }
}
